package com.xc.quickstart.common.aspect;

import com.alibaba.fastjson.JSON;
import com.xc.quickstart.common.context.ApiContext;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
@Order(2)
@Slf4j
public class LogControllerAspect {

    @Pointcut("execution(* com.xc.quickstart.*.controller.*.*(..))")
    private void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Instant begin = new Date().toInstant();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

        log.info("[LogControllerAspect]调用开始 params:{},args:{},requestUrl:{},crmTraceId:{}"
                , methodSignature.getParameterNames()
                , joinPoint.getArgs()
                , JSON.toJSONString(request.getRequestURL())
                , ApiContext.getCrmTraceId());

        Object proceed = joinPoint.proceed();
        String result = JSON.toJSONString(proceed);
        Instant end = new Date().toInstant();

        log.info("[LogControllerAspect]调用结束 params:{},args:{},requestUrl:{},response:{},cost:{},speed:{},headerMap:{}"
                , methodSignature.getParameterNames()
                , joinPoint.getArgs()
                , JSON.toJSONString(request.getRequestURL())
                , JSON.toJSONString(result)
                , Duration.between(begin, end).toMillis()
                , Duration.between(begin, end).toMillis() > 500 ? "<<slow>>" : "<<fast>>"
                , getHeaderMap(request));
        return proceed;
    }

    @AfterReturning("pointcut()")
    public void afterReturning() {
        ApiContext.removeApiContextModel();
    }

    private Map<String, String> getHeaderMap(HttpServletRequest request) {
        Enumeration<String> headerNames = request.getHeaderNames();
        Map<String, String> headerMap = new HashMap<>();

        while (headerNames.hasMoreElements()) {
            String headName = headerNames.nextElement();
            String headValue = request.getHeader(headName);
            headerMap.put(headName, headValue);
        }
        return headerMap;
    }
}
